﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls.WebParts;
using System.Reflection;
using System.ComponentModel;

namespace EnhancedWebPart
{
    public class EnhancedWebPart : WebPart
    {
        /// <summary>
        /// If you need to use some extra DisplayableClasses for displaying your own classes,
        /// you can use this method to add them from specified assembly list
        /// For example, use:
        ///   return new array Assembly[] { new Assembly(typeof(EnhancedWebPart.SharePoint.DisplayableSPUser)) };
        /// if you are using Sharepoint
        /// </summary>
        protected virtual IEnumerable<Assembly> GetCompositionAssemblies()
        {
            return new List<Assembly>();
        }

        /// <summary>
        /// Override this method to add your own custom editor parts, if you need this.
        /// By default, EnhancedWebPart will automatically create one editor part for each
        /// property category ([Category("category-name-here")] attribute), and one for
        /// all the properties, which were not marked with Category attrubute
        /// </summary>
        protected virtual IEnumerable<EditorPart> GetAdditionalEditorParts()
        {
            return new List<EditorPart>();
        }

        /// <summary>
        /// This method is sealed and cannot be overriden in EnhancedWebPart
        /// If you need to create your custom editor parts, use <see cref="GetAdditionalEditorParts">GetAdditionalEditorParts</cref>
        /// </summary>
        public override sealed EditorPartCollection CreateEditorParts()
        {
            // initialize service locator
            ServiceLocator.Current.Initialize(
                GetCompositionAssemblies()
                .Concat(new Assembly[]
                    {
                        Assembly.GetExecutingAssembly(),
                        Assembly.GetCallingAssembly()
                    })
                );

            // создаем набор частей редактора
            List<EditorPart> editorParts = new List<EditorPart>(1);

            List<PropertyInfo> enhancedProperties = new List<PropertyInfo>();

            foreach (PropertyInfo pi in this.GetType().GetProperties())
            {
                if (pi.GetCustomAttributes(typeof(EnhancedWebPartPropertyAttribute), false).Count() != 0)
                {
                    enhancedProperties.Add(pi);
                }
            }

            if (enhancedProperties.Count > 0)
            {
                Dictionary<string, List<string>> editorPartsData = new Dictionary<string, List<string>>();
                foreach (PropertyInfo pi in enhancedProperties)
                {
                    CategoryAttribute categoryAttribute = (CategoryAttribute)pi.GetCustomAttributes(typeof(CategoryAttribute), false).FirstOrDefault();
                    if (categoryAttribute != null)
                    {
                        if (!editorPartsData.ContainsKey(categoryAttribute.Category))
                            editorPartsData.Add(categoryAttribute.Category, new List<string>());

                        editorPartsData[categoryAttribute.Category].Add(pi.Name);
                    }
                    else
                    {
                        if (!editorPartsData.ContainsKey("Preferences"))
                            editorPartsData.Add(categoryAttribute.Category, new List<string>());

                        editorPartsData["Preferences"].Add(pi.Name);
                    }
                }

                int i = 0;
                foreach (string key in editorPartsData.Keys)
                {
                    EditorPart part = new EnhancedEditorPart(editorPartsData[key].ToArray());
                    part.ID = "EnhancedEditorPart" + i.ToString();
                    part.Title = key;
                    i++;
                    editorParts.Add(part);
                }

            }

            editorParts.AddRange(GetAdditionalEditorParts());

            EditorPartCollection baseParts = base.CreateEditorParts();

            // создаем одну коллекцию с коллекцией редакторов базового класса и возвращем общую коллекцию как того требует интерфейс IWebEditable
            return new EditorPartCollection(baseParts, editorParts);
        }
    }
}
